// Copyright (c) 2019 Presto Labs Pte. Ltd.
// Author: chensili

#pragma once

#include <memory>
#include <optional>
#include <string>
#include <vector>

#include "coin2/exchange/base/symbology/spot_product.h"
#include "coin2/exchange/base/symbology/util.h"
#include "coin2/exchange/coinone/symbology/currency.h"

namespace coin2::exchange::coinone::symbology {

class CoinoneProduct
    : public base::symbology::SpotProduct<CoinoneCurrency, CoinoneProduct>,
      public base::symbology::ProductFromStrMixin<CoinoneProduct> {
 public:
  typedef SpotProduct<CoinoneCurrency, CoinoneProduct> BaseProduct;

  CoinoneProduct(
      const CoinoneCurrency& base,
      const CoinoneCurrency& quote) :
    SpotProduct(
        base,
        quote,
        ToCoinoneOrderNativeProduct(base, quote),
        ToCoinoneFeedNativeProduct(base, quote),
        base::market::ExchangeType::Coinone) { }

 public:
  static std::unique_ptr<CoinoneProduct> FromNativeStrImpl(
      const std::string& native_product,
      int64_t resolve_timestamp) {
    std::unique_ptr<CoinoneCurrency> base_ptr;
    std::unique_ptr<CoinoneCurrency> quote_ptr;
    bool success = ParseCoinoneNativeProduct(
      native_product, resolve_timestamp, &base_ptr, &quote_ptr);
    if (success) {
      return std::make_unique<CoinoneProduct>(*base_ptr, *quote_ptr);
    } else {
      return { };
    }
  }

 private:
  static bool ParseCoinoneNativeProduct(
      const std::string& product_str,
      int64_t resolve_timestamp,
      std::unique_ptr<CoinoneCurrency>* base_ptr,
      std::unique_ptr<CoinoneCurrency>* quote_ptr) {
    const std::string& product_str_upper = StringToUpperCopy(product_str);
    std::string currency_base = product_str_upper;
    std::string currency_quote = "KRW";
    if (auto pos = product_str.find('-'); pos != std::string::npos) {
      std::vector<std::string> splitted;
      splitted = Split(product_str_upper, "-");
      currency_base = splitted[0];
      currency_quote = splitted[1];
    }
    *base_ptr = CoinoneCurrency::FromNativeStrNoThrow(currency_base, resolve_timestamp);
    *quote_ptr = CoinoneCurrency::FromNativeStrNoThrow(currency_quote, resolve_timestamp);
    return true;
  }

  static std::string ToCoinoneOrderNativeProduct(
      const CoinoneCurrency& base,
      const CoinoneCurrency& quote) {
    using base::market::MarketType;
    if (quote.currency() == "KRW") {
      return base.native_currency(MarketType::Spot);
    } else {
      return base.native_currency(MarketType::Spot) + "-" + quote.native_currency(MarketType::Spot);
    }
  }

  static std::string ToCoinoneFeedNativeProduct(
      const CoinoneCurrency& base,
      const CoinoneCurrency& quote) {
    using base::market::MarketType;
    return base.native_currency(MarketType::Spot) + "-" + quote.native_currency(MarketType::Spot);
  }
};

}  // namespace coin2::exchange::coinone::symbology
